package org.aldar.bquest.logic.controller.player;

import android.util.Log;
import org.aldar.bquest.constants.IConstants;
import org.aldar.bquest.effects.SymbolAnimationUtil;
import org.aldar.bquest.entity.effect.ParticleUtil;
import org.aldar.bquest.entity.pool.TilesPool;
import org.aldar.bquest.resources.ResourceManager;
import org.aldar.bquest.screens.MainBoardScreen;
import org.aldar.bquest.util.Logger;
import org.andengine.engine.handler.timer.ITimerCallback;
import org.andengine.engine.handler.timer.TimerHandler;
import org.andengine.entity.Entity;
import org.andengine.entity.IEntity;
import org.andengine.entity.modifier.*;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.sprite.TiledSprite;
import org.andengine.entity.text.Text;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.util.modifier.IModifier;

import java.util.LinkedList;
import java.util.List;
import java.util.Random;

public class ManaAndPointsController implements IConstants {

    private static Logger LOG = new Logger(ManaAndPointsController.class);

    private static int MANA_START_Y = 20;
    private static int MANA_HEIGHT = 100;

    private static float MANA_WIDTH = 10;

    private static float MANA_START_X = 20;

    public static float MANA_TARGET_X = 50;
    public static float MANA_TARGET_Y = 50;

    public static float POINTS_TARGET_X = CAMERA_WIDTH - 50;
    public static float POINTS_TARGET_Y = 50;

    private Entity bonusLayer;
    private float currentManaAmount;

    private TiledSprite movesLeftText = null;
    private Text pointsText = null;
    private TiledSprite filledMana;
    private VertexBufferObjectManager vertexBufferObjectManager;

    private static ManaAndPointsController instance;

    private int currentPoints = 0;
    private int pointsToAdd = 0;
    private int availableTurns = 0;

    private int amountToAdd = 0;


    private Entity manaShine;
    private List<Entity> manaShineParticles;
    private Sprite manaRedBg;

    public ManaAndPointsController() {
        instance = this;
        pointsText = new Text(CAMERA_WIDTH - 70, 35, ResourceManager.getInstance().getFontTrebuchetBoldGold(), String.valueOf(currentPoints), vertexBufferObjectManager);
        MainBoardScreen.getScm().getTestLayer().attachChild(pointsText);
    }

    public static ManaAndPointsController getInstance() {
        return instance;
    }

    public void initEmptyManaAndSkills() {
        currentManaAmount = defaultManaInitialAmount;
        manaShineParticles = new LinkedList<Entity>();
        updateMana();
        //updateConcerts();
    }

    public void setBonusLayer(Entity bonusLayer) {
        this.bonusLayer = bonusLayer;
    }

    public synchronized boolean subtractMana(int amount) {
        if (currentManaAmount <= 0) {
            //do nothing - mana is zero
            return true;
        }
        //prevent overflow
        if (currentManaAmount - amount <= 0) {
            currentManaAmount = 0;
        } else {
            currentManaAmount -= amount;
        }
        /* not showing "minus" mana any more
        Text symbolText = new Text(0, 0, ResourceManager.getInstance().getBigFont(), "-" + amount, vertexBufferObjectManager);
        symbolText.setColor(Color.WHITE);
        SymbolAnimationUtil.moveSymbolUp(symbolText.getX(), symbolText.getY(), symbolText);
        */

        updateMana();
        return currentManaAmount <= 0;
    }


    public synchronized void addMana(int amount) {
        if (currentManaAmount >= maxManaAmount) {
            //do nothing - mana is full
            return;
        }
        currentManaAmount += amount;
        //prevent overflow
        if (currentManaAmount >= maxManaAmount) {
            currentManaAmount = maxManaAmount;
            //setSkillButtonsReady();
        }
        //update will be done in ModifierFinished of particle track
        //updateMana();
    }

    public synchronized void fireCollectedManaSymbol() {
        int finalAmount = amountToAdd;
        int turnsadded = amountToAdd / manaUseForMatch;
        if (finalAmount > 0) {
            final TiledSprite manaSymbol = TilesPool.getEntityForTiledTexture(ResourceManager.getInstance().getManaSymbolRegion());
            int tileIndex;
            if (turnsadded == 0) {
                return;
            }
            if (turnsadded == 1) {
                tileIndex = 0;
            } else if (turnsadded == 2) {
                tileIndex = 1;
            } else if (turnsadded == 3) {
                tileIndex = 2;
            } else if (turnsadded == 4) {
                tileIndex = 3;
            } else if (turnsadded < 10) {
                tileIndex = 4;
            } else if (turnsadded < 15) {
                tileIndex = 5;
            } else {
                tileIndex = 6;
            }
            manaSymbol.setCurrentTileIndex(tileIndex);
            MainBoardScreen.getInstanceEngine().registerUpdateHandler(new TimerHandler(IConstants.CRYSTAL_COLLECT_DURATION * 0.75f, new ITimerCallback() {
                @Override
                public void onTimePassed(TimerHandler pTimerHandler) {
                    SymbolAnimationUtil.moveSymbolUp(70, 70, manaSymbol);
                }
            }));
        }
        //reset values
        amountToAdd = 0;
    }

    public synchronized void fireCollectedPointsSymbol(float startX, float startY) {
        int tileIndex = 0;
        if (pointsToAdd <= 10) {
            tileIndex = 0;
        } else if (pointsToAdd > 10 && pointsToAdd <= 20) {
            tileIndex = 1;
        } else if (pointsToAdd > 3 && pointsToAdd <= 50) {
            tileIndex = 2;
        } else if (pointsToAdd > 4 && pointsToAdd <= 100) {
            tileIndex = 3;
        } else if (pointsToAdd > 5 && pointsToAdd <= 500) {
            tileIndex = 4;
        } else if (pointsToAdd > 500) {
            tileIndex = 5;
        }
        TiledSprite symbolText = TilesPool.getEntityForTiledTexture(ResourceManager.getInstance().getPointsSymbolRegion());
        symbolText.setCurrentTileIndex(tileIndex);
        SymbolAnimationUtil.moveSymbolUp(CAMERA_WIDTH - 70, 70, symbolText);
        //reset values
        pointsToAdd = 0;
    }

    public void addPoints(int points, int multiplier, float startX, float startY) {
        currentPoints += points;
        pointsToAdd = points;

        if (multiplier == 2) {
            Entity multiplierSymbol = TilesPool.getEntityForTexture(ResourceManager.getInstance().getSymbolX2());
            SymbolAnimationUtil.moveSymbolUp(startX, startY, multiplierSymbol);
        } else if (multiplier >= 3) {
            Entity multiplierSymbol = TilesPool.getEntityForTexture(ResourceManager.getInstance().getSymbolX3());
            SymbolAnimationUtil.moveSymbolUp(startX, startY, multiplierSymbol);
        }

        fireCollectedPointsSymbol(POINTS_TARGET_X, POINTS_TARGET_Y);
        //ParticleUtil.makeParticlePath(startX, startY, POINTS_TARGET_X, POINTS_TARGET_Y, ResourceManager.getInstance().getGoldParticleRegion());
        ParticleUtil.makeCoinPath(startX, startY, POINTS_TARGET_X, POINTS_TARGET_Y, 3, MainBoardScreen.getScm().getBonusLayer());
        if (pointsText != null) {
            pointsText.detachSelf();
        }
        pointsText = new Text(CAMERA_WIDTH - 70, 35, ResourceManager.getInstance().getFontTrebuchetBoldGold(), String.valueOf(currentPoints), vertexBufferObjectManager);
        MainBoardScreen.getScm().getTestLayer().attachChild(pointsText);
        pointsText.registerEntityModifier(new SequenceEntityModifier(
                new ScaleModifier(0.2f, 1, 2),
                new ScaleModifier(0.2f, 2, 1)
        ));
    }

    public synchronized void updateMana() {
        stopWarningAnimation();
        final float filledManaPercentage = currentManaAmount / maxManaAmount;
        //Log.i("mana", "filled mana percentage "+filledManaPercentage);
        if (filledMana == null) {
            filledMana = new TiledSprite(MANA_START_X, MANA_START_Y, ResourceManager.getInstance().getManaFillingRegion(), vertexBufferObjectManager);
            filledMana.setAnchorCenter(0, 0);
            filledMana.setAlpha(0.5f);
            int filledManaProcent = (int) (filledManaPercentage * 100) - 1;
            if (filledManaProcent < 0) {
                filledMana.setVisible(false);
            } else {
                filledMana.setVisible(true);
                //Log.i("mana", "filled mana percentage "+filledManaProcent);
                filledMana.setCurrentTileIndex(filledManaProcent);
            }
            manaRedBg = TilesPool.getEntityForTexture(ResourceManager.getInstance().getManaRedBg(), vertexBufferObjectManager);
            manaRedBg.setAnchorCenter(0, 0);
            manaRedBg.setPosition(0, 0);
            MainBoardScreen.getScm().getBgLayer().attachChild(manaRedBg);
            manaRedBg.setAlpha(0f);
            manaShine = new Entity();
            MainBoardScreen.getScm().getBgLayer().attachChild(manaShine);
            MainBoardScreen.getScm().getBgLayer().attachChild(filledMana);
        }

        if (movesLeftText == null) {
            movesLeftText = TilesPool.getEntityForTiledTexture(ResourceManager.getInstance().getMovesLeft());
            movesLeftText.setPosition(0, 0);
            movesLeftText.setAnchorCenter(0, 0);
            bonusLayer.attachChild(movesLeftText);
        }

        try {
            int newAvailableTurns = 0;
            newAvailableTurns = ((int) currentManaAmount) / manaUseForMatch;
            if (currentManaAmount - newAvailableTurns * manaUseForMatch > 0) {
                newAvailableTurns++;
            }
            Log.i("loony ManaAndPointsController", "update text new available turns= " + newAvailableTurns + " mana= " + currentManaAmount);
            if (newAvailableTurns != availableTurns) {
                availableTurns = newAvailableTurns;
                //MainBoardScreen.getInstance().getGameSound().stopTicTacSound();
                LOG.i("availableTurns = " + availableTurns);
                movesLeftText.clearEntityModifiers();
                if (availableTurns > 5) {
                    movesLeftText.setAlpha(0);
                } else if (availableTurns <= 0) {
                    manaRedBg.setAlpha(1);
                    movesLeftText.setAlpha(0);
                } else {
                    movesLeftText.setCurrentTileIndex(availableTurns - 1);
                    manaRedBg.setAlpha(1);
                    movesLeftText.setAlpha(1);
                    //MainBoardScreen.getInstance().getGameSound().playTicTacSound(availableTurns);
                    movesLeftText.registerEntityModifier(new LoopEntityModifier(
                            new ParallelEntityModifier(
                                    new SequenceEntityModifier(
                                            new ScaleAtModifier(0.15f + 0.07f * availableTurns, 1, 1.1f, 0.5f, 0.5f),
                                            new ScaleAtModifier(0.15f + 0.07f * availableTurns, 1.1f, 1, 0.5f, 0.5f, new IEntityModifier.IEntityModifierListener() {
                                                @Override
                                                public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                                                    MainBoardScreen.getInstance().getGameSound().stopTicTacSound();
                                                }

                                                @Override
                                                public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                                                    MainBoardScreen.getInstance().getGameSound().playTicTacSound(5);
                                                }
                                            })
                                    ),
                                    new SequenceEntityModifier(
                                            new AlphaModifier(0.15f + 0.07f * availableTurns, 0.7f, 1f),
                                            new AlphaModifier(0.15f + 0.07f * availableTurns, 1f, 0.7f)
                                    )

                            )
                    ));
                }
            }
        } catch (Exception e) {
            LOG.e("text exception", e);
        }
        filledMana.clearEntityModifiers();
        filledMana.setAlpha(0.5f);
        final int filledManaProcent = (int) (filledManaPercentage * 100) - 1;
        final int currentManaTileIndex = filledMana.getCurrentTileIndex();
        filledMana.registerEntityModifier(new SequenceEntityModifier(
                new DelayModifier(IConstants.CRYSTAL_COLLECT_DURATION * 0.75f),
                new DelayModifier(0.5f, new IEntityModifier.IEntityModifierListener() {
                    @Override
                    public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                    }

                    @Override
                    public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                        if (filledManaProcent < 0) {
                            filledMana.setVisible(false);
                        } else {
                            filledMana.setVisible(true);
                            manaRedBg.setAlpha(0);
                            //Log.i("mana", "filled mana percentage "+filledManaProcent);
                        }
                        if (availableTurns <= 5 && availableTurns > 0) {
                            filledMana.registerEntityModifier(getManaBlinkingModifier());
                            manaRedBg.setAlpha(1);
                        }
                    }
                }) {
                    @Override
                    protected void onManagedUpdate(float pSecondsElapsed, IEntity pEntity) {
                        super.onManagedUpdate(pSecondsElapsed, pEntity);    //To change body of overridden methods use File | Settings | File Templates.
                        float percentage = getSecondsElapsed() / getDuration();
                        filledMana.setCurrentTileIndex((int) (currentManaTileIndex + (filledManaProcent - currentManaTileIndex) * percentage));

                    }
                }
        ));
        refreshManaShine();


    }

    private synchronized void refreshManaShine() {
        for (Entity p : manaShineParticles) {
            p.clearEntityModifiers();
            p.detachSelf();

            TilesPool.pushEntityToStack((Sprite) p);
        }

        manaShineParticles.clear();
        int particlesCount = (int) currentManaAmount / 10 + 3;
        for (int i = 0; i < particlesCount; i++) {
            float[] xy = generateParticleCoordinates();
            if (xy == null) {
                continue;
            }
            //Log.i("mana", "Generated Y coord: " + xy[1] + " max is " + (20 + currentManaAmount));
            ITextureRegion particleRegion = null;
            if (availableTurns > 5) {
                particleRegion = ResourceManager.getInstance().getParticleRegion();
            } else {
                particleRegion = ResourceManager.getInstance().getRedParticleRegion();
            }
            final Sprite particle = TilesPool.getEntityForTexture(particleRegion);
            //final Entity particle = new Rectangle(0,0,5,5,vertexBufferObjectManager);
            manaShineParticles.add(particle);
            particle.setX(xy[0]);
            particle.setY(xy[1]);
            particle.setScale(0f);
            particle.setAnchorCenter(0.5f, 0.5f);
            manaShine.attachChild(particle);
            particle.registerEntityModifier(new LoopEntityModifier(
                    new SequenceEntityModifier(
                            new DelayModifier(1f + new Random().nextInt(300) / 100f),
                            new ScaleAtModifier(0.5f, 0, 1, 0.5f, 0.5f),
                            new ScaleAtModifier(0.5f, 1, 0, 0.5f, 0.5f, new IEntityModifier.IEntityModifierListener() {
                                @Override
                                public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
                                }

                                @Override
                                public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
                                    float[] xy = generateParticleCoordinates();
                                    if (xy != null) {
                                        particle.setX(xy[0]);
                                        particle.setY(xy[1]);
                                    }
                                }
                            })
                    )
            ));

        }
    }

    private float[] generateParticleCoordinates() {
        float[] result = new float[2];
        float centerX = 70f;
        float centerY = 70f;
        //float maxParticleY = 15f + 100*filledManaPercentage; //upper margin for particle coordinates
        double distanceToCenter;
        int trial = 0;
        result[0] = 20 + new Random().nextInt(100);
        do {
            //float randomAngle = (float) (Math.PI * 2 * new Random().nextFloat());
            //float randomRadius = 45*new Random().nextFloat();
            //result[0] = (float) (randomRadius * Math.cos(randomAngle) + centerX);
            //result[1] = (float) (randomRadius * Math.sin(randomAngle) + centerY);
            result[1] = 20 + new Random().nextInt((int) currentManaAmount + 1) * 0.8f; //+1 because argument of random cannot be zero!
            distanceToCenter = Math.sqrt(Math.pow(result[0] - centerX, 2) + Math.pow(result[1] - centerY, 2));
        } while (distanceToCenter > 50 && trial++ < 100);
        if (distanceToCenter > 50) return null;
        return result;
    }

    private IEntityModifier getManaBlinkingModifier() {
        return new LoopEntityModifier(
                new SequenceEntityModifier(
                        new AlphaModifier(0.5f, 0.8f, 0.5f),
                        new AlphaModifier(0.5f, 0.5f, 0.8f)
                )
        );
    }

    public IEntityModifier startWarningAnimation() {
        filledMana.clearEntityModifiers();
        AlphaModifier fade = new AlphaModifier(0.5f, 1, 0);
        AlphaModifier reveal = new AlphaModifier(0.5f, 0, 1);

        SequenceEntityModifier sequenceEntityModifier = new SequenceEntityModifier(fade, reveal) {
            @Override
            protected void onModifierFinished(IEntity pItem) {
                super.reset();
            }
        };
        sequenceEntityModifier.setAutoUnregisterWhenFinished(false);
        return sequenceEntityModifier;
    }

    public void stopWarningAnimation() {
        if (filledMana != null) {
            filledMana.setAlpha(1f);
            filledMana.clearEntityModifiers();
        }
    }


    public void setVertexBufferObjectManager(VertexBufferObjectManager vertexBufferObjectManager) {
        this.vertexBufferObjectManager = vertexBufferObjectManager;
    }

    public void addPartialMana(int amountAddForCrystal) {
        addMana(amountAddForCrystal);
        amountToAdd += amountAddForCrystal;
    }


    public float getCurrentManaAmount() {
        return currentManaAmount;
    }

    public void stopBlinking() {
        if (movesLeftText != null) {
            movesLeftText.clearEntityModifiers();
        }
    }
}
